package com.ruyiadmin.springboot.controller.system;

import com.alibaba.fastjson.JSON;
import com.ruyiadmin.springboot.common.annotations.system.Log;
import com.ruyiadmin.springboot.common.annotations.system.Permission;
import com.ruyiadmin.springboot.common.beans.system.SystemCacheConfig;
import com.ruyiadmin.springboot.common.components.core.RuYiRedisComponent;
import com.ruyiadmin.springboot.common.core.business.enums.OperationType;
import com.ruyiadmin.springboot.common.core.system.entities.ActionResult;
import com.ruyiadmin.springboot.common.core.system.entities.QueryResult;
import com.ruyiadmin.springboot.common.exceptions.RuYiAdminCustomException;
import com.ruyiadmin.springboot.domain.dto.system.OrgUserTreeDTO;
import com.ruyiadmin.springboot.domain.dto.system.SysOrganizationDTO;
import com.ruyiadmin.springboot.domain.dto.system.SysUserDTO;
import com.ruyiadmin.springboot.domain.entity.system.SysOrganization;
import com.ruyiadmin.springboot.service.iservices.system.ISysOrganizationService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 机构表 前端控制器
 * </p>
 *
 * @author RuYiAdmin
 * @since 2022-07-12
 */
@RestController
@RequestMapping("/OrganizationManagement")
@Api(tags = "系统机构管理服务")
@RequiredArgsConstructor
public class SysOrganizationController {

    //region 服务私有属性

    private final RuYiRedisComponent redisUtils;
    private final SystemCacheConfig systemCacheConfig;
    private final ISysOrganizationService organizationService;
    private final ModelMapper modelMapper;

    //endregion

    //region 查询机构列表

    @PostMapping("/Post")
    @ApiOperation(value = "查询机构列表")
    @Log(OperationType = OperationType.QueryList)
    @Permission(permission = "org:query:list")
    public QueryResult<SysOrganizationDTO> getOrgTreeNodes() throws Exception {
        return this.organizationService.getOrgTreeNodes();
    }

    //endregion

    //region 查询机构信息

    @GetMapping("/GetById/{orgId}")
    @ApiOperation(value = "查询机构信息")
    @Log(OperationType = OperationType.QueryEntity)
    @Permission(permission = "org:query:list")
    public ActionResult getById(@PathVariable("orgId") String orgId) {
        Object value = this.redisUtils.get(this.systemCacheConfig.getOrgCacheName());
        List<SysOrganizationDTO> orgs = JSON.parseArray(value.toString(), SysOrganizationDTO.class);
        return ActionResult.success(orgs.stream().
                filter(t -> t.getId().equals(orgId)).
                collect(Collectors.toList()).
                get(0));
    }

    //endregion

    //region 新增机构信息

    @PostMapping("/Add")
    @ApiOperation(value = "新增机构信息")
    @Log(OperationType = OperationType.AddEntity)
    @Permission(permission = "org:add:entity")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult addOrg(@Valid @RequestBody SysOrganization org) {
        ActionResult actionResult = ActionResult.success(this.organizationService.save(org));

        //region 数据一致性维护

        Object value = this.redisUtils.get(this.systemCacheConfig.getOrgCacheName());
        List<SysOrganizationDTO> orgs = JSON.parseArray(value.toString(), SysOrganizationDTO.class);
        SysOrganizationDTO orgDTO = this.modelMapper.map(org, SysOrganizationDTO.class);
        orgs.add(orgDTO);
        this.redisUtils.set(this.systemCacheConfig.getOrgCacheName(), JSON.toJSONString(orgs));

        //endregion

        return actionResult;
    }

    //endregion

    //region 编辑机构信息

    @PutMapping("/Put")
    @ApiOperation(value = "编辑机构信息")
    @Log(OperationType = OperationType.EditEntity)
    @Permission(permission = "org:edit:entity")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult editOrg(@Valid @RequestBody SysOrganization org) {
        ActionResult actionResult = ActionResult.success(this.organizationService.updateById(org));

        //region 数据一致性维护

        Object value = this.redisUtils.get(this.systemCacheConfig.getOrgCacheName());
        List<SysOrganizationDTO> orgs = JSON.parseArray(value.toString(), SysOrganizationDTO.class);

        //删除旧数据
        for (Iterator<SysOrganizationDTO> iterator = orgs.iterator(); iterator.hasNext(); ) {
            SysOrganizationDTO element = iterator.next();
            if (element.getId().equals(org.getId())) {
                iterator.remove();
                break;
            }
        }

        //数据转换
        SysOrganizationDTO orgDTO = this.modelMapper.map(org, SysOrganizationDTO.class);
        if (!StringUtils.isEmpty(orgDTO.getLeader())) {
            //设置领导人姓名
            value = this.redisUtils.get(this.systemCacheConfig.getUserCacheName());
            List<SysUserDTO> users = JSON.parseArray(value.toString(), SysUserDTO.class);
            users = users.stream().
                    filter(t -> t.getId().equals(orgDTO.getLeader())).
                    collect(Collectors.toList());
            SysUserDTO user = users.size() > 0 ? users.get(0) : null;
            if (user != null) {
                orgDTO.setLeaderName(user.getDisplayName());
            }
        }

        //添加新数据
        orgs.add(orgDTO);
        this.redisUtils.set(this.systemCacheConfig.getOrgCacheName(), JSON.toJSONString(orgs));

        //endregion

        return actionResult;
    }

    //endregion

    //region 删除机构信息

    @DeleteMapping("/DeleteRange/{ids}")
    @ApiOperation(value = "删除机构信息")
    @Log(OperationType = OperationType.DeleteEntity)
    @Permission(permission = "org:del:entities")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult deleteRange(@PathVariable("ids") String ids) {
        //机构删除检测
        this.deleteCheck(ids);

        //删除数据
        List<String> array = Arrays.asList(ids.split(","));
        ActionResult actionResult = ActionResult.success(this.organizationService.removeByIds(array));

        //region 数据一致性维护

        Object value = this.redisUtils.get(this.systemCacheConfig.getOrgCacheName());
        List<SysOrganizationDTO> orgs = JSON.parseArray(value.toString(), SysOrganizationDTO.class);

        for (String item : array) {
            for (Iterator<SysOrganizationDTO> iterator = orgs.iterator(); iterator.hasNext(); ) {
                SysOrganizationDTO element = iterator.next();
                if (element.getId().equals(item)) {
                    iterator.remove();
                    break;
                }
            }
        }

        this.redisUtils.set(this.systemCacheConfig.getOrgCacheName(), JSON.toJSONString(orgs));

        //endregion

        return actionResult;
    }

    //endregion

    //region 获取机构用户树

    @PostMapping("/GetOrgUserTree")
    @ApiOperation(value = "获取机构用户树")
    @Log(OperationType = OperationType.QueryList)
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public QueryResult<OrgUserTreeDTO> getOrgUserTree() throws Exception {
        return this.organizationService.getOrgUserTree();
    }

    //endregion

    //region 机构删除检测

    /**
     *机构删除检测
     *
     * @param ids 编号数组
     */
    private void deleteCheck(String ids) {
        Object value = this.redisUtils.get(this.systemCacheConfig.getOrgCacheName());
        List<SysOrganizationDTO> orgs = JSON.parseArray(value.toString(), SysOrganizationDTO.class);

        value = this.redisUtils.get(this.systemCacheConfig.getUserCacheName());
        List<SysUserDTO> users = JSON.parseArray(value.toString(), SysUserDTO.class);

        String[] array = ids.split(",");
        //删除校验
        for (String item : array) {
            int orgSize = (int) orgs.stream().
                    filter(t -> !StringUtils.isEmpty(t.getParentId())).
                    filter(t -> t.getParentId().equals(item)).count();

            int userSize = (int) users.stream().
                    filter(t -> !StringUtils.isEmpty(t.getOrgId())).
                    filter(t -> t.getOrgId().equals(item)).count();

            if (orgSize > 0 || userSize > 0) {
                throw new RuYiAdminCustomException("org contains users or sub orgs,can not be deleted");
            }
        }

    }

    //endregion

}
